#pragma once

#include "Containers/Optional.h"
#include "Containers/Variant.h"
#include "ScriptCompiler/Token/FilePosition.h"
#include "ScriptRuntime/ScriptInnerType.h"

#include "Containers/String.h"

enum class EScriptTokenType
{
    Unknow,
    EndOfFile,
    Identifier,      // only allow '_' [a-z] [A-Z] [0-9]  and any non-ascii char
    LiteralNumber,          // only allow [0-9] '-' '.'
    LiteralString,       
    LiteralChar,   
    LiteralBool,  
    
    CommitHead,        //"//" 
    LenEnd,            //"\n"

    //operators 
    PlusPlus,          //++
    MinOverloadOperator = PlusPlus,
    MinusMinus,         //--
    Plus ,              //+
    Minus,              //-
    Multiply,           //*
    Divide,             // '/'
    Mod,                // %
    Equal,              // ==
    NotEqual,           // !=
    Less,               // <
    LessEqual,          // <=
    Greater,            // >
    GreaterEqual,       // >=
    NotOperator,        // !
    Tilde,              // ~
    And,                // &   bit and
    Xor,                // ^
    Or,                 // |   bit or
    LeftShift,          // <<
    RightShift,         // >>

    MaxOverloadOperator=RightShift,

    LeftParentheses ,   //  (
    RightParentheses,   //  )
    LeftBracket ,       //  [
    RightBracket ,      //  ]
    LeftBrace,          //  {
    RightBrace,         //  }    
    Dot,                // .
    Arrow,              // ->
    Comma,              //,
    Semicolon,          // ;
    Colon,              // :
    Assign,             // =


    AndAnd,             // &&
    OrOr,               // ||
  

    PlusAssign,          // +=
    MinusAssign,        // -=
    MultiplyAssign,     // *=
    DivideAssign,       // /=
    ModAssign,          // %=
    AndAssign,          // &=
    OrAssign,           // |=
    XorAssign,          // ^=
    LeftShiftAssign,    // <<=
    RightShiftAssign,   // >>=
    Question,           // ?
    LambdaOperator,     // =>
    At,                 // @


    //Basic Types
    InnerType,          //int ,float ,double ,bool ,char ,string ,void
    // String,            //utf32 string
    // Float,             //float32 in cpp
    // Double,            //double in cpp
    // Decimal,           //128bit float 
    // Void,
    // Bool,
    // Char,              //32bit char 
    // Sbyte,               // int8_t in cpp
    // Byte,            // uint8_t in cpp
    // Short,           // int16_t in cpp
    // Ushort,          // uint16_t in cpp
    // Int,              // int  ,int32 in cpp
    // Uint,            // uint ,uint32 in cpp
    // Long,              // int64_t in cpp
    // Ulong,            // uint64_t in cpp

    //keywords

    Abstract,
    As,
    Add,
    Async,
    Await,
    Alias,
    
    By,
    Base,
    Break,

    Case,
    Catch,
    Checked,
    Class,
    Const,
    Continue,
    


    Dynamic,
    Do,
    Default,
    Delegate,
    

    Explicit,
    Else,
    Enum,
    Event,
    Extern,


    Fixed,
    Finally,
    From,
    For,
    Foreach,


    Get,
    Global,
    Group,
    Goto,

    Implicit,
    In,
    Is,
    Interface,
    Internal,
    Into,
    Init,
    If,




    Join,
    
    Let,
    Lock,
    
    Namespace,
    New,
    Null,
    Not,
    NotNull,
    Nuint,


    Out,
    On,
    Operator,
    OrderBy,
    Override,

    
    Partial,
    Params,
    Private,
    Protected,
    Public,

    Ref,
    Remove,
    Return,
    Readonly,
    Record,

    Sizeof,
    Sealed,
    Select,
    Set,
    Stackalloc,
    Static,
    Struct,
    Switch,


    This,
    Throw,
    Try,
    Typeof,


    Unchecked,
    Unsafe,
    Using,


    Value,
    Var,
    Virtual,
    Volatile,

    When,
    Where,
    While,
    With,

    Yield,



    


    KeyWordMax,
};

class CScriptToken
{
public:    
 

    CScriptToken(EScriptTokenType InTokenType,const SScriptFilePosition & InFilePosition)
    {
        Type=InTokenType;

        FilePosition=InFilePosition;
    } 

    CScriptToken( bool InValue , const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::LiteralBool;
        LiteralValue=InValue;
        FilePosition=InFilePosition;
    }


    CScriptToken(const CString& InName,const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::LiteralString;
        LiteralValue=InName;

        FilePosition=InFilePosition;
    }


    CScriptToken(uint64_t InValue,const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::LiteralNumber;
        LiteralValue=InValue;
        FilePosition=InFilePosition;
    }

    CScriptToken(double InValue,const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::LiteralNumber;
        LiteralValue=InValue;
        FilePosition=InFilePosition;
    }

    CScriptToken(char32_t InValue,const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::LiteralChar;
        LiteralValue=InValue;
        FilePosition=InFilePosition;
    }

    CScriptToken(EScriptInnerType InInnerType,const SScriptFilePosition & InFilePosition)
    {
        Type=EScriptTokenType::InnerType;
        InnerType=InInnerType;
        FilePosition=InFilePosition;
    }


    EScriptTokenType Type=EScriptTokenType::Unknow;

    TOptional<TVariant<CString,uint64_t,double,char32_t,bool>> LiteralValue;

    TOptional<EScriptInnerType> InnerType;

    SScriptFilePosition FilePosition={0,0,0};

    CString ToString() const;

};


namespace Token
{
    WHENGINE_API bool IsAssignOperator(EScriptTokenType InType);
   

}